package cc.verywell.pureblock.util.sign;

import java.nio.ByteBuffer;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.NoSuchAlgorithmException;
import java.security.PublicKey;
import java.security.Signature;
import java.security.SignatureException;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.ShortBufferException;

import cc.verywell.pureblock.log.Pblog;
import cc.verywell.pureblock.util.SignClient;

/**
* 
*
* @author TanYaqiu 
* @address flat 601
* @date 2019年2月25日 上午12:11:30
*/
public class EcClient implements SignClient {
	static final String ENCRYPT_NAME_GEN = EcServer.ENCRYPT_NAME_GEN ;
	static final String ENCRYPT_NAME = EcServer.ENCRYPT_NAME ;
	static final String SIGN_NAME = EcServer.SIGN_NAME ;

	protected PublicKey pk;
	final protected Cipher encode,decode;
	final protected Signature signature;
	
	public EcClient(byte[] pk) throws NoSuchAlgorithmException, InvalidKeySpecException {
		this(publicKey(pk));
	}
	static PublicKey publicKey(byte[] pk) throws NoSuchAlgorithmException, InvalidKeySpecException {
		X509EncodedKeySpec x509EncodedKeySpec = new X509EncodedKeySpec(pk);
		KeyFactory keyFactory = KeyFactory.getInstance(ENCRYPT_NAME_GEN);
		return keyFactory.generatePublic(x509EncodedKeySpec);
	}
	public EcClient(PublicKey publicKey) {
		this.pk = publicKey;
		Cipher cipher;
		try {
			cipher = encode = Cipher.getInstance(ENCRYPT_NAME);
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			cipher = decode = Cipher.getInstance(ENCRYPT_NAME);
			cipher.init(Cipher.DECRYPT_MODE, publicKey);
			signature = Signature.getInstance(SIGN_NAME);
			signature.initVerify(publicKey);
		} catch (InvalidKeyException | NoSuchAlgorithmException | NoSuchPaddingException e) {
			if(Pblog.INIT)Pblog.INIT(e);
			throw new RuntimeException(e);
		}
	}

	
	public PublicKey getKey() {
		return pk;
	}
	
	/**
	 * 通过应原来大小，返回加密后大小;
	 */
	public int outputLength(int inputLength) {
		return encode.getOutputSize(inputLength);
	}
	public int encode(ByteBuffer one) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		int s = encode.doFinal(one.array(), one.position()+one.arrayOffset(), one.remaining(), one.array(), one.position()+one.arrayOffset());
		one.limit(one.position()+s);
		return s;
	}
	public int encode(ByteBuffer input,ByteBuffer output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		return encode.doFinal(input, output);
	}
	
	
	/**
	 * 必须要等于大于 ，并且为此数的倍数才能开始解压;
	 */
	public int blockSize() {
		return decode.getBlockSize();
	}
	public int decode(ByteBuffer one) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		int s = decode.doFinal(one.array(), one.position()+one.arrayOffset(), one.remaining(), one.array(), one.position()+one.arrayOffset());
		one.limit(one.position()+s);
		return s;
	}
	public int decode(ByteBuffer input,ByteBuffer output) throws ShortBufferException, IllegalBlockSizeException, BadPaddingException {
		return decode.doFinal(input, output);
	}

	/**
	 * https://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Signature
	 * @param src
	 * @param sign
	 * @return
	 * @throws SignatureException 
	 */
	public boolean check(ByteBuffer bb,byte[] sign) throws SignatureException {
        //3.验证签名【公钥验证】
        signature.update(bb);
        return signature.verify(sign);
        //System.out.println("数字签名是否有效？" + bool);
	}

}
